package cn.hamster3.mc.plugin.ball.common.listener;

import cn.hamster3.mc.plugin.ball.common.api.BallAPI;
import cn.hamster3.mc.plugin.ball.common.entity.BallPlayerInfo;
import cn.hamster3.mc.plugin.ball.common.entity.BallServerInfo;
import cn.hamster3.mc.plugin.ball.common.event.BallActions;
import cn.hamster3.mc.plugin.ball.common.event.message.MessageReceivedEvent;
import cn.hamster3.mc.plugin.ball.common.event.operate.*;
import cn.hamster3.mc.plugin.ball.common.event.player.*;
import cn.hamster3.mc.plugin.ball.common.event.server.ServerOfflineEvent;
import cn.hamster3.mc.plugin.ball.common.event.server.ServerOnlineEvent;
import cn.hamster3.mc.plugin.core.common.api.CoreAPI;
import com.google.common.eventbus.Subscribe;

public class BallCommonListener {
    public static final BallCommonListener INSTANCE = new BallCommonListener();

    private BallCommonListener() {
    }

    @Subscribe
    public void onMessageReceived(MessageReceivedEvent message) {
        String channel = message.getChannel();
        if (!BallAPI.BALL_CHANNEL.equals(channel)) {
            return;
        }
        switch (BallActions.valueOf(message.getAction())) {
            // operate type
            case BroadcastPlayerMessage: {
                BroadcastPlayerMessageEvent event = CoreAPI.getInstance().getGson().fromJson(message.getContent(), BroadcastPlayerMessageEvent.class);
                BallAPI.getInstance().getEventBus().post(event);
                break;
            }
            case DispatchConsoleCommand: {
                DispatchConsoleCommandEvent event = CoreAPI.getInstance().getGson().fromJson(message.getContent(), DispatchConsoleCommandEvent.class);
                BallAPI.getInstance().getEventBus().post(event);
                break;
            }
            case DispatchPlayerCommand: {
                DispatchPlayerCommandEvent event = CoreAPI.getInstance().getGson().fromJson(message.getContent(), DispatchPlayerCommandEvent.class);
                BallAPI.getInstance().getEventBus().post(event);
                break;
            }
            case KickPlayer: {
                KickPlayerEvent event = CoreAPI.getInstance().getGson().fromJson(message.getContent(), KickPlayerEvent.class);
                BallAPI.getInstance().getEventBus().post(event);
                break;
            }
            case SendMessageToPlayer: {
                SendMessageToPlayerEvent event = CoreAPI.getInstance().getGson().fromJson(message.getContent(), SendMessageToPlayerEvent.class);
                BallAPI.getInstance().getEventBus().post(event);
                break;
            }
            case SendPlayerToLocation: {
                SendPlayerToLocationEvent event = CoreAPI.getInstance().getGson().fromJson(message.getContent(), SendPlayerToLocationEvent.class);
                BallAPI.getInstance().getEventBus().post(event);
                break;
            }
            case SendPlayerToPlayer: {
                SendPlayerToPlayerEvent event = CoreAPI.getInstance().getGson().fromJson(message.getContent(), SendPlayerToPlayerEvent.class);
                BallAPI.getInstance().getEventBus().post(event);
                break;
            }

            // player type
            case BallPlayerPreLogin: {
                BallPlayerPreLoginEvent event = CoreAPI.getInstance().getGson().fromJson(message.getContent(), BallPlayerPreLoginEvent.class);
                BallAPI.getInstance().getEventBus().post(event);
                break;
            }
            case BallPlayerLogin: {
                BallPlayerLoginEvent event = CoreAPI.getInstance().getGson().fromJson(message.getContent(), BallPlayerLoginEvent.class);
                BallAPI.getInstance().getEventBus().post(event);
                break;
            }
            case BallPlayerPostLogin: {
                BallPlayerPostLoginEvent event = CoreAPI.getInstance().getGson().fromJson(message.getContent(), BallPlayerPostLoginEvent.class);
                BallAPI.getInstance().getEventBus().post(event);
                break;
            }
            case BallPlayerPreConnectServer: {
                BallPlayerPreConnectServerEvent event = CoreAPI.getInstance().getGson().fromJson(message.getContent(), BallPlayerPreConnectServerEvent.class);
                BallAPI.getInstance().getEventBus().post(event);
                break;
            }
            case BallPlayerPostConnectServer: {
                BallPlayerPostConnectServerEvent event = CoreAPI.getInstance().getGson().fromJson(message.getContent(), BallPlayerPostConnectServerEvent.class);
                BallAPI.getInstance().getEventBus().post(event);
                break;
            }
            case BallPlayerLogout: {
                BallPlayerLogoutEvent event = CoreAPI.getInstance().getGson().fromJson(message.getContent(), BallPlayerLogoutEvent.class);
                BallAPI.getInstance().getEventBus().post(event);
                break;
            }

            // server type
            case ServerOffline: {
                ServerOfflineEvent event = CoreAPI.getInstance().getGson().fromJson(message.getContent(), ServerOfflineEvent.class);
                BallAPI.getInstance().getEventBus().post(event);
                break;
            }
            case ServerOnline: {
                ServerOnlineEvent event = CoreAPI.getInstance().getGson().fromJson(message.getContent(), ServerOnlineEvent.class);
                BallAPI.getInstance().getEventBus().post(event);
                break;
            }
        }
    }

    @Subscribe
    public void handlePlayerInfo(MessageReceivedEvent message) {
        if (!message.getChannel().contains(BallAPI.PLAYER_INFO_CHANNEL)) {
            return;
        }
        if (BallActions.valueOf(message.getAction()) != BallActions.BallPlayerInfoUpdate) {
            return;
        }
        BallPlayerInfoUpdateEvent event = CoreAPI.getInstance().getGson().fromJson(message.getContent(), BallPlayerInfoUpdateEvent.class);
        BallAPI.getInstance().getEventBus().post(event);
    }

    @Subscribe
    public void onBallPlayerInfoUpdate(BallPlayerInfoUpdateEvent event) {
        BallPlayerInfo info = event.getPlayerInfo();
        BallAPI.getInstance().getAllPlayerInfo().put(info.getUuid(), info);
    }

    @Subscribe
    public void onServerOnline(ServerOnlineEvent event) {
        BallServerInfo info = event.getServerInfo();
        BallAPI.getInstance().getAllServerInfo().put(info.getId(), info);
        switch (info.getType()) {
            case GAME: {
                BallAPI.getInstance().getAllPlayerInfo().forEach((uuid, playerInfo) -> {
                    if (playerInfo.getGameServer().equals(info.getId())) {
                        playerInfo.setOnline(false);
                    }
                });
                break;
            }
            case PROXY: {
                BallAPI.getInstance().getAllPlayerInfo().forEach((uuid, playerInfo) -> {
                    if (playerInfo.getProxyServer().equals(info.getId())) {
                        playerInfo.setOnline(false);
                    }
                });
                break;
            }
        }
    }

    @Subscribe
    public void onServerOffline(ServerOfflineEvent event) {
        String serverID = event.getServerID();
        BallServerInfo info = BallAPI.getInstance().getAllServerInfo().remove(serverID);
        if (info == null) {
            return;
        }
        switch (info.getType()) {
            case GAME: {
                BallAPI.getInstance().getAllPlayerInfo().forEach((uuid, playerInfo) -> {
                    if (playerInfo.getGameServer().equals(info.getId())) {
                        playerInfo.setOnline(false);
                    }
                });
                break;
            }
            case PROXY: {
                BallAPI.getInstance().getAllPlayerInfo().forEach((uuid, playerInfo) -> {
                    if (playerInfo.getProxyServer().equals(info.getId())) {
                        playerInfo.setOnline(false);
                    }
                });
                break;
            }
        }
    }
}
